#include "stdlib.hpp"
#include <purewell/types.hpp>
#include <purewell/file.hpp>
#include <purewell/pairfile.hpp>
#include <purewell/iopoll.hpp>

#include <map>
using namespace std;

#include "iopollepoll.hpp"

namespace purewell
{

#if defined(HAVE_EPOLL_CTL)

PWIOPollEPoll::PWIOPollEPoll() : m_epoll_fd(-1)
{
}

PWIOPollEPoll::~PWIOPollEPoll()
{
}

bool
PWIOPollEPoll::add(PWPairFile* pfile, size_t idx, int event)
{
	const int fd(pfile->getHandle(idx));

	m_fds.insert(fdmap_t::value_type(fd, pfile));
	struct epoll_event ev;
	ev.data.ptr = pfile;
	ev.events = event;
	bool res(0 == epoll_ctl(m_epoll_fd,
		EPOLL_CTL_ADD,
		fd,
		&ev));
	_PWTRACE("%s", strerror(errno));
	return res;
}

bool
PWIOPollEPoll::add(PWFile* pfile, int event)
{
	const int fd(pfile->getHandle());

	m_fds.insert(fdmap_t::value_type(fd, pfile));
	struct epoll_event ev;
	ev.data.ptr = pfile;
	ev.events = event;
	bool res(0 == epoll_ctl(m_epoll_fd,
		EPOLL_CTL_ADD,
		fd,
		&ev));
	_PWTRACE("%s", strerror(errno));
	return res;
}

bool
PWIOPollEPoll::modify(PWPairFile* pfile, size_t idx, int event)
{
	const int fd(pfile->getHandle(idx));

	struct epoll_event ev;
	ev.data.ptr = pfile;
	ev.events = event;
	bool res(0 == epoll_ctl(m_epoll_fd,
		EPOLL_CTL_MOD,
		fd,
		&ev));
	_PWTRACE("%s", strerror(errno));
	return res;
}

bool
PWIOPollEPoll::modify(PWFile* pfile, int event)
{
	const int fd(pfile->getHandle());

	struct epoll_event ev;
	ev.data.ptr = pfile;
	ev.events = event;
	bool res(0 == epoll_ctl(m_epoll_fd,
		EPOLL_CTL_MOD,
		fd,
		&ev));
	_PWTRACE("%s", strerror(errno));
	return res;
}

bool
PWIOPollEPoll::remove(PWPairFile* pfile, size_t idx)
{
	const int fd(pfile->getHandle(idx));

	m_fds.erase(fd);

	bool res(0 == epoll_ctl(m_epoll_fd,
		EPOLL_CTL_DEL,
		fd,
		NULL));
	_PWTRACE("%s", strerror(errno));
	return res;
}

bool
PWIOPollEPoll::remove(PWFile* pfile)
{
	const int fd(pfile->getHandle());

	m_fds.erase(fd);

	bool res(0 == epoll_ctl(m_epoll_fd,
		EPOLL_CTL_DEL,
		fd,
		NULL));
	_PWTRACE("%s", strerror(errno));
	return res;
}

bool
PWIOPollEPoll::dispatch(int msec)
{
	const int ret(epoll_wait(m_epoll_fd,
		m_epoll_events,__PW_EPOLL_DISPATCH_SIZE,
		msec));
	if ( -1 == ret )
	{
		_PWTRACE("%s", strerror(errno));
		return false;
	}

	int i(0);
	fdmap_citr it;
	while ( i < ret )
	{
		const struct epoll_event& ev(m_epoll_events[i]);
		if ( m_fds.end() != (it = m_fds.find(ev.data.fd)) )
		{
			it->second->onEvent(this, ev.data.fd, ev.events);
		}
		++i;
	}

	return true;
}

const char*
PWIOPollEPoll::getType(void) const
{
	static const char type[] = "epoll";
	return type;
}

bool
PWIOPollEPoll::initialize(void* param)
{
	const int fd(epoll_create(__PW_EPOLL_SIZE));
	if ( -1 == fd )
	{
		_PWTRACE("%s", strerror(errno));
		return false;
	}

	m_epoll_fd = fd;
	return true;
}

void
PWIOPollEPoll::destroy(void)
{
	if ( -1 != m_epoll_fd )
	{
		::close(m_epoll_fd);
		m_epoll_fd = -1;
	}

	m_fds.clear();
}

#endif//HAVE_EPOLL_CTL

};//namespace purewell

